//
// Created by YueChuan on 2023/4/29.
//

#ifndef __YUECHUAN_HTTP_H
#define __YUECHUAN_HTTP_H

#include <memory>
#include <string>
#include <map>
#include <iostream>
#include <vector>
#include <boost/lexical_cast.hpp>
#include "util.h"

namespace yuechuan {
    namespace http {
        class HttpResponse;
        /* 请求方法 */
#define HTTP_METHOD_MAP(XX)         \
          XX(0,  DELETE,      DELETE)       \
          XX(1,  GET,         GET)          \
          XX(2,  HEAD,        HEAD)         \
          XX(3,  POST,        POST)         \
          XX(4,  PUT,         PUT)          \
          /* pathological */                \
          XX(5,  CONNECT,     CONNECT)      \
          XX(6,  OPTIONS,     OPTIONS)      \
          XX(7,  TRACE,       TRACE)        \
          /* WebDAV */                      \
          XX(8,  COPY,        COPY)         \
          XX(9,  LOCK,        LOCK)         \
          XX(10, MKCOL,       MKCOL)        \
          XX(11, MOVE,        MOVE)         \
          XX(12, PROPFIND,    PROPFIND)     \
          XX(13, PROPPATCH,   PROPPATCH)    \
          XX(14, SEARCH,      SEARCH)       \
          XX(15, UNLOCK,      UNLOCK)       \
          XX(16, BIND,        BIND)         \
          XX(17, REBIND,      REBIND)       \
          XX(18, UNBIND,      UNBIND)       \
          XX(19, ACL,         ACL)          \
          /* subversion */                  \
          XX(20, REPORT,      REPORT)       \
          XX(21, MKACTIVITY,  MKACTIVITY)   \
          XX(22, CHECKOUT,    CHECKOUT)     \
          XX(23, MERGE,       MERGE)        \
          /* upnp */                        \
          XX(24, MSEARCH,     M-SEARCH)     \
          XX(25, NOTIFY,      NOTIFY)       \
          XX(26, SUBSCRIBE,   SUBSCRIBE)    \
          XX(27, UNSUBSCRIBE, UNSUBSCRIBE)  \
          /* RFC-5789 */                    \
          XX(28, PATCH,       PATCH)        \
          XX(29, PURGE,       PURGE)        \
          /* CalDAV */                      \
          XX(30, MKCALENDAR,  MKCALENDAR)   \
          /* RFC-2068, section 19.6.1.2 */  \
          XX(31, LINK,        LINK)         \
          XX(32, UNLINK,      UNLINK)       \
          /* icecast */                     \
          XX(33, SOURCE,      SOURCE)       \

        /* 状态码 */
#define HTTP_STATUS_MAP(XX)                                                 \
          XX(100, CONTINUE,                        Continue)                        \
          XX(101, SWITCHING_PROTOCOLS,             Switching Protocols)             \
          XX(102, PROCESSING,                      Processing)                      \
          XX(200, OK,                              OK)                              \
          XX(201, CREATED,                         Created)                         \
          XX(202, ACCEPTED,                        Accepted)                        \
          XX(203, NON_AUTHORITATIVE_INFORMATION,   Non-Authoritative Information)   \
          XX(204, NO_CONTENT,                      No Content)                      \
          XX(205, RESET_CONTENT,                   Reset Content)                   \
          XX(206, PARTIAL_CONTENT,                 Partial Content)                 \
          XX(207, MULTI_STATUS,                    Multi-Status)                    \
          XX(208, ALREADY_REPORTED,                Already Reported)                \
          XX(226, IM_USED,                         IM Used)                         \
          XX(300, MULTIPLE_CHOICES,                Multiple Choices)                \
          XX(301, MOVED_PERMANENTLY,               Moved Permanently)               \
          XX(302, FOUND,                           Found)                           \
          XX(303, SEE_OTHER,                       See Other)                       \
          XX(304, NOT_MODIFIED,                    Not Modified)                    \
          XX(305, USE_PROXY,                       Use Proxy)                       \
          XX(307, TEMPORARY_REDIRECT,              Temporary Redirect)              \
          XX(308, PERMANENT_REDIRECT,              Permanent Redirect)              \
          XX(400, BAD_REQUEST,                     Bad Request)                     \
          XX(401, UNAUTHORIZED,                    Unauthorized)                    \
          XX(402, PAYMENT_REQUIRED,                Payment Required)                \
          XX(403, FORBIDDEN,                       Forbidden)                       \
          XX(404, NOT_FOUND,                       Not Found)                       \
          XX(405, METHOD_NOT_ALLOWED,              Method Not Allowed)              \
          XX(406, NOT_ACCEPTABLE,                  Not Acceptable)                  \
          XX(407, PROXY_AUTHENTICATION_REQUIRED,   Proxy Authentication Required)   \
          XX(408, REQUEST_TIMEOUT,                 Request Timeout)                 \
          XX(409, CONFLICT,                        Conflict)                        \
          XX(410, GONE,                            Gone)                            \
          XX(411, LENGTH_REQUIRED,                 Length Required)                 \
          XX(412, PRECONDITION_FAILED,             Precondition Failed)             \
          XX(413, PAYLOAD_TOO_LARGE,               Payload Too Large)               \
          XX(414, URI_TOO_LONG,                    URI Too Long)                    \
          XX(415, UNSUPPORTED_MEDIA_TYPE,          Unsupported Media Type)          \
          XX(416, RANGE_NOT_SATISFIABLE,           Range Not Satisfiable)           \
          XX(417, EXPECTATION_FAILED,              Expectation Failed)              \
          XX(421, MISDIRECTED_REQUEST,             Misdirected Request)             \
          XX(422, UNPROCESSABLE_ENTITY,            Unprocessable Entity)            \
          XX(423, LOCKED,                          Locked)                          \
          XX(424, FAILED_DEPENDENCY,               Failed Dependency)               \
          XX(426, UPGRADE_REQUIRED,                Upgrade Required)                \
          XX(428, PRECONDITION_REQUIRED,           Precondition Required)           \
          XX(429, TOO_MANY_REQUESTS,               Too Many Requests)               \
          XX(431, REQUEST_HEADER_FIELDS_TOO_LARGE, Request Header Fields Too Large) \
          XX(451, UNAVAILABLE_FOR_LEGAL_REASONS,   Unavailable For Legal Reasons)   \
          XX(500, INTERNAL_SERVER_ERROR,           Internal Server Error)           \
          XX(501, NOT_IMPLEMENTED,                 Not Implemented)                 \
          XX(502, BAD_GATEWAY,                     Bad Gateway)                     \
          XX(503, SERVICE_UNAVAILABLE,             Service Unavailable)             \
          XX(504, GATEWAY_TIMEOUT,                 Gateway Timeout)                 \
          XX(505, HTTP_VERSION_NOT_SUPPORTED,      HTTP Version Not Supported)      \
          XX(506, VARIANT_ALSO_NEGOTIATES,         Variant Also Negotiates)         \
          XX(507, INSUFFICIENT_STORAGE,            Insufficient Storage)            \
          XX(508, LOOP_DETECTED,                   Loop Detected)                   \
          XX(510, NOT_EXTENDED,                    Not Extended)                    \
          XX(511, NETWORK_AUTHENTICATION_REQUIRED, Network Authentication Required) \

        /**
         * @brief HTTP方法枚举
         */
        enum class HttpMethod {
#define XX(num, name, string) name = num,
            HTTP_METHOD_MAP(XX)
#undef XX
            INVALID_METHOD
        };
        /**
         * @brief HTTP状态枚举
         */
        enum class HttpStatus {
#define XX(code, name, desc) name = code,
            HTTP_STATUS_MAP(XX)
#undef XX
        };

        /**
         * @brief 将std::string 类型 转成自定义的HttpMethod 枚举类类型
         * @param m 要转换的字符串
         * @return
         */
        HttpMethod StringToHttpMethod(const std::string &m);

        /**
         * @brief 将char* 类型 转换成自定义的HttpMethod 枚举类类型
         * @param chr 要转换的字符指针
         * @return
         */
        HttpMethod CharsToHttpMethod(const char *chr);

        /**
         * @brief 将自定义类型的HttpMethod 枚举类类型 转换成 字符指针 类型
         * @param method 自定义类型
         * @return
         */
        char *HttpMethodToChars(const HttpMethod &method);

        /**
         * @brief 将自定义类型的 HttpMethod 枚举类类型 转换成 字符串 类型
         * @param method 自定义类型
         * @return
         */
        const char *HttpMethodToString(const HttpMethod &method);

        /**
         * @brief 将自定义乐行的 httpStatus 枚举类类型 转换成 字符指针 类型
         * @param status 自定义leixing
         * @return
         */
        const char *HttpStatusToString(const HttpStatus &status);

        /**
         * @brief 大小写无关
         */
        struct CaseInsensitiveLess {
            bool operator()(const std::string lhs, const std::string rhs) const;
        };

        class HttpRequest {
        public:
            typedef std::shared_ptr<HttpRequest> ptr;
            typedef std::map<std::string, std::string, CaseInsensitiveLess> MapType;

            /**
             * @brief 含参构造函数
             * @param version http协议的版本，默认为1.1
             * @param close 是否是长连接，默认为true
             */
            HttpRequest(uint8_t version = 0X11, bool close = true);

            /**
             * @brief 创建一个响应对象
             * @return
             */
            std::shared_ptr<HttpResponse> createResponse();

            /**
             * @brief 获取请求的方法
             * @return
             */
            HttpMethod getMethod() const { return m_method; }

            /**
             * @brief 设置请求的方法
             * @param method 方法
             * @return
             */
            void setMethod(HttpMethod &method) { m_method = method; }

            /**
             * @brief 获取请求的状态
             * @return
             */
            HttpStatus getStatus() const { return m_status; }

            /**
             * @brief 设置请求的状态
             * @param status
             */
            void setStatus(HttpStatus &status) { m_status = status; }

            /**
             * @brief 获取请求的协议版本
             * @return
             */
            uint8_t getVersion() const { return m_version; }

            /**
             * @brief 设置请求的协议版本
             * @param version 协议版本 使用一个字节的十六禁止表示 0X11表示1.1 0X10表示1.0版本
             */
            void setVersion(uint8_t version) { m_version = version; }

            /**
             * @brief 是否是长连接
             * @return bool
             */
            bool isClose() const { return m_close; }

            /**
             * @brief 设置长连接状态
             * @param close 是否为长连接
             */
            void setClose(bool close) { m_close = close; }

            /**
             * @brief 是否是webSocket
             * @return bool
             */
            bool isWebSocket() const { return m_webSocket; }

            /**
             * @brief 设置是否为webSocket
             * @param webSocket 是否为webSocket
             */
            void setWebSocket(bool webSocket) { m_webSocket = webSocket; }

            /**
             * @brief 获取请求路径
             * @return std::string
             */
            std::string getPath() const { return m_path; }

            /**
             * @brief 设置请求路径
             * @param path
             */
            void setPath(std::string path) { m_path = path; }

            /**
             * @brief 获取请求参数
             * @return std::string
             */
            std::string getQuery() const { return m_query; }

            /**
             * @brief 设置请求参数
             * @param query 要设置的请求参数字符串
             */
            void setQuery(std::string query) { m_query = query; }

            /**
             * @brief 获取附加字符
             * @return std::string
             */
            std::string getFragment() const { return m_fragment; }

            /**
             * @brief 设置附加字符
             * @param fragment 要添加的附加字符
             */
            void setFragment(std::string fragment) { m_fragment = fragment; }

            /**
             * @brief 获取请求体
             * @return std::string
             */
            std::string getBody() const { return m_body; }

            /**
             * @brief 设置请求体
             * @param body 请求体
             */
            void setBody(std::string body) { m_body = body; }

            /**
             * @brief 获取请求文件流
             * @return std::ostream
             */
            std::ostrean& getFileOstream() { return m_fileOstream; }

            /**
             * @brief 设置请求文件流
             * @param body 要设置的请求流
             */
            void setFileOStream(std::ostream& ss) { m_fileOstream = ss; }

            /**
             * @brief 获取所有请求头
             * @return std::map<std::string, std::string, CaseInsensitiveLess>
             */
            const MapType &getHeaders() const { return m_headers; }

            /**
             * @brief 设置请求头
             * @param mapType 要设置的请求头字典
             */
            void setHeaders(MapType &mapType) { m_headers = mapType; }

            /**
             * @brief 获取请求参数
             * @return std::map<std::string, std::string, CaseInsensitiveLess>
             */
            const MapType &getParams() const { return m_params; }

            /**
             * @brief 设置请求参数
             * @param mapType 要设置的请求参数字典
             */
            void setParams(MapType &mapType) { m_params = mapType; }

            /**
             * @brief 获取请求cookie
             * @return std::map<std::string, std::string, CaseInsensitiveLess>
             */
            const MapType &getCookies() const { return m_cookies; }

            /**
             * @brief 设置请求cookie
             * @param mapType 要设置的请求cookie 字典
             */
            void setCookies(MapType &mapType) { m_cookies = mapType; }


            /**
             * @brief 来获取请求头中对应的
             * @details
                        * 当请求头中没有该键对应的值时，则将def作为默认返回
             * @param key 要查询的键
             * @param def 默认的值
             * @return std::string 查询到的字符
             */
            std::string getHeader(const std::string &key, const std::string &def = "");

            /**
             * @brief 设置请求头中的子段
             * @param key 要添加的键
             * @param value 要添加的值
             */
            void setHeader(const std::string &key, const std::string &value);

            /**
             * @brief 查询请求头中是否有key键对应的键值对
             * @details
                        * 若有则将值赋值给val
                        * 若没有val就是默认的nullptr
             * @param key 要查询的键
             * @param val 要保存的值
             * @return bool 是否查询到
             */
            bool hasHeader(const std::string &key, std::string *val = nullptr);

            /**
             * @brief 删除请求头中的键对应的键值对
             * @param key 要删除的键值
             */
            void delHeader(const std::string &key);


            /**
             * @brief 获取请求体中的键值对
             * @details
                        * 当请求体中没有该键时，则使用def作为值进行返回
             * @param key 要获取的键值对中的键
             * @param def 默认的值
             * @return std::string 获取到的键值对中的值
             */
            std::string getParam(const std::string &key, const std::string &def = "");

            /**
             * @brief 设置请求体中的键值对
             * @param key 要设置的键
             * @param value 要设置的值
             */
            void setParam(const std::string &key, const std::string &value);

            /**
             * @brief 查询请求体中是否有对应的键值对
             * @details
                        * 若有，则将值传递给val
                        * 若没有，则val就是默认值为nullptr
             * @param key 要查询的键
             * @param val 要保存的值
             * @return bool 是否查询到
             */
            bool hasParam(const std::string &key, std::string *val = nullptr);

            /**
             * @brief 删除请求体中的键值对
             * @param key 要删除的键
             */
            void delParam(const std::string &key);


            /**
             * @brief 获取cookie中的键值对
             * @details
                        * 当cookie中没有key对应的键值对是，则使用默认的def作为返回值
             * @param key 要获取的键
             * @param def 默认的值
             * @return std::string 请求体中的键对应的值
             */
            std::string getCookie(const std::string &key, const std::string &def = "");

            /**
             * @brief 设置cookie中的键值对
             * @param key 要设置的键
             * @param value 要设置的值
             */
            void setCookie(const std::string &key, const std::string &value);

            /**
             * @brief 查询请求体中的键值对
             * @details
                        * 当cookie中没有对应的键时，val使用默认的nullptr
                        * 当查询到时，val赋值为对应的值
             * @param key 要查询的键
             * @param val 保存查询到的值
             * @return
             */
            bool hasCookie(const std::string &key, std::string *val = nullptr);

            /**
             * @brief 删除cookie中对应的键值对
             * @param key 要删除的键
             */
            void delCookie(const std::string &key);

            /**
             * @brief 将请求头中的值强转为T类型
             * @tparam T 请求头中值的类型
             * @param key 请求头中 键
             * @param val 请求头中 值(结果保存在此)
             * @param def 请求头中默认的值
             * @return bool 是否转换成功
             */
            template<class T>
            bool checkGetHeaderAs(const std::string &key, T &val, const T &def = T()) {
                return checkGetAs(m_headers, key, val, def);
            }

            /**
             * @brief 将请求头中的值强转为T类型
             * @tparam T 请求头中的值类型
             * @param key 请求头中 键
             * @param def 请求头中默认值
             * @return T 转换后的值
             */
            template<class T>
            T getHeaderAs(const std::string &key, const T &def = T()) {
                return getAs(m_headers, key, def);
            }

            /**
             * @brief 将请求体中的值强转为T类型
             * @tparam T 请求体中值的类型
             * @param key 请求体中 键
             * @param val 请求体中 值(结果保存在此)
             * @param def 请求体中默认的值
             * @return bool 是否转换成功
             */
            template<class T>
            bool checkGetParamAs(const std::string &key, T &val, const T &def = T()) {
                initBodyParam();
                initQueryParam();
                return checkGetAs(m_params, key, val, def);
            }

            /**
             * @brief 将请求体中的值强转为T类型
             * @tparam T 请求体中的值类型
             * @param key 请求体中 键
             * @param def 请求体中默认值
             * @return T 转换后的值
             */
            template<class T>
            T getParamAs(const std::string &key, const T &def = T()) {
                initBodyParam();
                initQueryParam();
                return getAs(m_params, key, def);
            }

            /**
             * @brief 将cookie中的值强转为T类型
             * @tparam T cookie中值的类型
             * @param key cookie中 键
             * @param val cookie中 值(结果保存在此)
             * @param def cookie中默认的值
             * @return bool 是否转换成功
             */
            template<class T>
            bool checkGetCookieAs(const std::string &key, T &val, const T &def = T()) {
                initCookies();
                return checkGetAs(m_cookies, key, val, def);
            }

            /**
             * @brief 将cookie中的值强转为T类型
             * @tparam T cookie中的值类型
             * @param key cookie中 键
             * @param def cookie中默认值
             * @return T 转换后的值
             */
            template<class T>
            T getCookieAs(const std::string &key, const T &def = T()) {
                initCookies();
                return getAs(m_cookies, key, def);
            }

            /**
             * @brief 序列化到输出流中
             * @param os 输出流
             * @return
             */
            std::ostream &dump(std::ostream &os) const;

            /**
             * @brief 转化成字符串类型
             * @return std::string
             */
            std::string toString() const;

            /**
             * @brief 初始化
             */
            void init();

            /**
             * @brief 初始化参数
             */
            void initParam();

            /**
             * @brief 初始化查询参数
             */
            void initQueryParam();

            /**
             * @brief 初始化请求体参数
             */
            void initBodyParam();

            /**
             * @brief 初始化cookie
             */
            void initCookies();

        private:
            template<class T>
            bool checkGetAs(const MapType &m, const std::string &key, T &val, const T &def = T()) {
                std::string str;
                auto it = m.find(key);
                if (it == m.end()) {
                    val = def;
                    return false;
                }
                try {
                    val = boost::lexical_cast<T>(it->second);
                    return true;
                } catch (...) {
                    val = def;
                }
                return false;

            };
            template<class T>
            T getAs(const MapType &m, const std::string &key, const T &def = T()) {
                auto it = m.find(key);
                if (it == m.end()) {
                    return def;
                }
                try {
                    return boost::lexical_cast<T>(it->second);
                } catch (...) {
                    return def;
                }
            }


        private:
            /// 方法
            HttpMethod m_method;
            /// 状态
            HttpStatus m_status;
            /// http版本
            uint8_t m_version;
            /// 是否关闭, http1.1支持长连接
            bool m_close;
            /// 是否为webSocket
            bool m_webSocket;
            /// 是否已经解析过了  001解析了query，010解析了请求体，100解析了cookie
            uint8_t m_parseParamFlag;
            /// 路径
            std::string m_path;
            /// 请求参数
            std::string m_query;
            /// 其他字符
            std::string m_fragment;
            /// 请求体
            std::string m_body;
            ///TODO 对于文件上传的类型是否要新增一个文件类型
            std::string m_fileName;
            
            std::ostream m_fileOstream;

            /// 请求头
            MapType m_headers;
            /// 请求参数
            MapType m_params;
            /// cookies
            MapType m_cookies;

        };

        class HttpResponse {
        public:
            typedef std::shared_ptr<HttpResponse> ptr;

            typedef std::map<std::string, std::string, CaseInsensitiveLess> MapType;

            /**
             * @brief 含参构造函数
             * @param version 协议等级
             * @param close 是否长连接
             */
            HttpResponse(uint8_t version = 0X11, bool close = true);

            /**
             * @brief 获取响应状态
             * @return HttpStatus
             */
            HttpStatus getStatus() const { return m_status; }

            /**
             * @brief 设置响应状态
             * @param status 要设置的响应状态
             */
            void setStatus(HttpStatus status) { m_status = status; }

            /**
             * @brief 获取协议版本
             * @return uint8_t
             */
            uint8_t getVersion() const { return m_version; }

            /**
             * @brief 设置协议版本
             * @param version 要设置的协议版本
             */
            void setVersion(uint8_t version) { m_version = version; }

            /**
             * @brief 获取响应体
             * @return std::string
             */
            const std::string getBody() const { return m_body; }

            /**
             * @brief 设置响应体
             * @param body 要设置的响应体
             */
            void setBody(std::string body) { m_body = body; }

            /**
             * @brief 获取响应原因
             * @return const std::string
             */
            const std::string getReason() const { return m_reason; }

            /**
             * @brief 设置响应原因
             * @param reason 要设置的响应原因
             */
            void setReason(std::string reason) { m_reason = reason; }

            /**
             * @brief 获取响应头
             * @return std::map<std::string, std::string, CaseInsensitiveLess> m_cookies;
             */
            const MapType &getHeaders() const { return m_headers; }

            /**
             * @brief 设置响应头信息
             * @param map 要设置响应头字典
             */
            void setHeaders(const MapType &map) { m_headers = map; }

            /**
             * @brief 是否是长连接
             * @return bool
             */
            bool isClose() const { return m_close; }

            /**
             * @brief 设置长连接
             * @param close 是否是长连接
             */
            void setClose(bool close) { m_close = close; }

            /**
             * @brief 是否是webSocket
             * @return bool
             */
            bool isWebSocket() const { return m_webSocket; }

            /**
             * @brief 设置webSocket
             * @param webSocket 是否是webSocket
             */
            void setWebSocket(bool webSocket) { m_webSocket = webSocket; }

            /**
             * @brief 获取响应头中键对应的值
             * @param key 要获取的键
             * @param def 默认值
             * @return std::string
             */
            std::string getHeader(const std::string &key, const std::string &def = "") const;

            /**
             * @brief 设置响应头中的键值对
             * @param key 要设置的键
             * @param value 要设置的值
             */
            void setHeader(const std::string &key, const std::string &value);

            /**
             * @brief 删除响应头中的键值对
             * @param key 要删除的键
             */
            void delHeader(const std::string &key);

            template<class T>
            T getAs(const MapType &m, const std::string &key, const T &def = T()) {
                auto it = m.find(key);
                if (it == m.end()) {
                    return def;
                }
                try {
                    return boost::lexical_cast<T>(it->second);
                } catch (...) {
                    return def;
                }
            }
            template<class T>
            bool checkGetHeaderAs(const std::string &key, T &val, const T &def = T()) {
                return checkGetAs(m_headers, key, val, def);
            }

            /**
             * @brief 获取响应的头部参数
             * @tparam T 转换类型
             * @param key 关键字
             * @param def 默认值
             * @return 如果存在且转换成功返回对应的值,否则返回def
             */
            template<class T>
            T getHeaderAs(const std::string &key, const T &def = T()) {
                return getAs(m_headers, key, def);
            }

            /**
             * @brief 序列化输出到流
             * @param os 输出流
             * @return 输出流
             */
            std::ostream &dump(std::ostream &os) const;

            /**
             * @brief 转成字符串
             */
            std::string toString() const;

            void setRedirect(const std::string &uri);

            void setCookie(const std::string &key, const std::string &val,
                           time_t expired = 0, const std::string &path = "", const std::string &domain = "",
                           bool secure = false);

        private:
            /// 响应状态
            HttpStatus m_status;
            /// 协议版本
            uint8_t m_version;
            /// 响应体
            std::string m_body;
            ///TODO 是否要处理响应体是文件类型
            /// 响应码解析后的字符串
            std::string m_reason;
            /// 是否长连接
            bool m_close;
            /// 是否是websocket
            bool m_webSocket;

            /// 响应头信息
            MapType m_headers;
            /// cookies信息
            std::vector<std::string> m_cookies;

        };

        /**
         * @brief 流式输出HttpRequest
         * @param os 输出流
         * @param req Http请求
         * @return 输出流
         */
        std::ostream &operator<<(std::ostream &os, const HttpRequest &req);

        /**
         * @brief 流式输出HttpResponse
         * @param os 输出流
         * @param rsp Http响应
         * @return 输出流
         */
        std::ostream &operator<<(std::ostream &os, const HttpResponse &rsp);
    };//namespace http


};// namespace yuechuan
#endif //YUECHUAN_HTTP_H
